package service.impl;

import com.jfinal.aop.Before;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.tx.Tx;
import model.Product;
import model.Purchases;
import model.User;
import service.IPurchasesService;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by ykj on 16/1/8.
 */
public class PurchasesServiceImpl implements IPurchasesService {
    public Page findByPage(int page, int pageSize) {
        return Purchases.dao.paginate(page, pageSize, "select pur.*,p.name product_name,u.name user_name from purchases pur inner join product p on pur.product_id = p.id inner join user u on pur.user_id = u.id ");

    }

    @Before(Tx.class)
    public Model save(Model model) {
        Purchases purchases = (Purchases) model;
        purchases.setState(Purchases.CONFIRM_BUY);
        purchases.setCreateTime(new Date());

        //获取产品投资时长,填充购买有效时长
        Product product = Product.dao.findById(purchases.getProductId());
        if(product==null) return null;
        purchases.setValidDate(product.getNeedTime());

        //对比认购资金,最大认购不能超过产品募资总额
        double remaining = product.getTotalMoney() - product.getAlreadyMoney();
        //如果募资总额已满则不允许购买
        if(remaining == 0) return null;
        if(remaining < purchases.getInvest() ){
            purchases.setInvest(remaining);
        }
        product.setAlreadyMoney(product.getAlreadyMoney() + purchases.getInvest());

        //获取当前用户,减扣当前资金
        User user = User.dao.findById(purchases.getUserId());
        if(user==null) return null;
        double remainAsset = user.getAsset() - purchases.getInvest();
        //如果用户资金不足则不允许购买
        if(remainAsset>=0) {
            user.setAsset(user.getAsset() - purchases.getInvest());
        }else{
            return null;
        }

        product.update();
        user.update();
        boolean result = purchases.save();
        return result ? purchases : null;
    }

    public Model update(Model model) {
        Purchases purchases = (Purchases) model;
        boolean result = purchases.update();
        return result ? purchases : null;
    }

    public boolean delete(int id) {
        return Purchases.dao.deleteById(id);
    }

    public Model findById(int id) {
        return Purchases.dao.findById(id);
    }

    public Page findByUserId(int userId, int page, int pageSize) {
        return Purchases.dao.paginate(page, pageSize, "select pro.name,pro.rate_return,pur.* from purchases pur,product pro where pur.user_id = ? and pro.id = pur.product_id and pur.state = 802",userId);
    }

    public Page findAllByUserId(int userId, int page, int pageSize) {
        return Purchases.dao.paginate(page, pageSize, "select pro.name,pro.rate_return,pur.* from purchases pur inner join product pro on pro.id = pur.product_id where pur.user_id = ?",userId);
    }

    @Before(Tx.class)
    public double redeem(int userId, int purchasesId) throws Exception {
        Purchases purchases = Purchases.dao.findById(purchasesId);
        if(purchases==null) throw new Exception("purchases id error");
        User user = User.dao.findById(userId);
        if(user==null) throw new Exception("user id error");
        double invest = purchases.getInvest();
        Date createTime = purchases.getCreateTime();
        int productId = purchases.getProductId();
        Product product = Product.dao.findById(productId);
        if(product==null) throw new Exception("product is not exists");
        //产品购买所需平均时间
        long needTime = Long.valueOf(product.getNeedTime());
        Date currentTime = new Date();
        //实际已购买时间
        long day=(currentTime.getTime()-createTime.getTime())/(24*60*60*1000);
        if(day>needTime){
            day = needTime;
        }
        double rateReturn = product.getRateReturn();
        double earning = rateReturn/100/365*invest*day;
        DecimalFormat df = new DecimalFormat("#.00");
        //实际所获收益
        earning = Double.valueOf(df.format(earning));

        //持久化赎回记录
        user.setEarnings(user.getEarnings()+earning);
        user.setAsset(user.getAsset()+invest+earning);

        purchases.setRedeemTime(currentTime);
        purchases.setState(Purchases.CONFIRM_REDEMPTION);

        user.update();
        purchases.update();
        return earning;
    }

    public List<Double> monthBuyByUser(int userId) {
        String sql = "select " +
                "sum(case when month(`create_time`)=1 then (select sum(invest) from purchases where id = p1.id and month(`create_time`)=1) else 0 end) as 'jan'," +
                "sum(case when month(`create_time`)=2 then (select sum(invest) from purchases where id = p1.id and month(`create_time`)=2) else 0 end) as 'feb'," +
                "sum(case when month(`create_time`)=3 then (select sum(invest) from purchases where id = p1.id and month(`create_time`)=3) else 0 end) as 'mar'," +
                "sum(case when month(`create_time`)=4 then (select sum(invest) from purchases where id = p1.id and month(`create_time`)=4) else 0 end) as 'apr'," +
                "sum(case when month(`create_time`)=5 then (select sum(invest) from purchases where id = p1.id and month(`create_time`)=5) else 0 end) as 'may'," +
                "sum(case when month(`create_time`)=6 then (select sum(invest) from purchases where id = p1.id and month(`create_time`)=6) else 0 end) as 'jun'," +
                "sum(case when month(`create_time`)=7 then (select sum(invest) from purchases where id = p1.id and month(`create_time`)=7) else 0 end) as 'july'," +
                "sum(case when month(`create_time`)=8 then (select sum(invest) from purchases where id = p1.id and month(`create_time`)=8) else 0 end) as 'aug'," +
                "sum(case when month(`create_time`)=9 then (select sum(invest) from purchases where id = p1.id and month(`create_time`)=9) else 0 end) as 'sep'," +
                "sum(case when month(`create_time`)=10 then (select sum(invest) from purchases where id = p1.id and month(`create_time`)=10) else 0 end) as 'oct'," +
                "sum(case when month(`create_time`)=11 then (select sum(invest) from purchases where id = p1.id and month(`create_time`)=11) else 0 end) as 'nov'," +
                "sum(case when month(`create_time`)=12 then (select sum(invest) from purchases where id = p1.id and month(`create_time`)=12) else 0 end) as 'dec' " +
                "from purchases p1 where p1.user_id = ? group by p1.user_id";
        Record dataRecord = Db.findFirst(sql,userId);
        List<Double> datas = monthCal(dataRecord);
        System.out.println(datas.toString());
        return datas;
    }

    public List<Double> monthRedeemByUser(int userId) {
        String sql = "select " +
                "sum(case when month(`create_time`)=1 then (select sum(invest) from purchases where id = p1.id and state=804 and month(`create_time`)=1) else 0 end) as 'jan', " +
                "sum(case when month(`create_time`)=2 then (select sum(invest) from purchases where id = p1.id and state=804 and month(`create_time`)=2) else 0 end) as 'feb', " +
                "sum(case when month(`create_time`)=3 then (select sum(invest) from purchases where id = p1.id and state=804 and month(`create_time`)=3) else 0 end) as 'mar', " +
                "sum(case when month(`create_time`)=4 then (select sum(invest) from purchases where id = p1.id and state=804 and month(`create_time`)=4) else 0 end) as 'apr', " +
                "sum(case when month(`create_time`)=5 then (select sum(invest) from purchases where id = p1.id and state=804 and month(`create_time`)=5) else 0 end) as 'may', " +
                "sum(case when month(`create_time`)=6 then (select sum(invest) from purchases where id = p1.id and state=804 and month(`create_time`)=6) else 0 end) as 'jun', " +
                "sum(case when month(`create_time`)=7 then (select sum(invest) from purchases where id = p1.id and state=804 and month(`create_time`)=7) else 0 end) as 'july', " +
                "sum(case when month(`create_time`)=8 then (select sum(invest) from purchases where id = p1.id and state=804 and month(`create_time`)=8) else 0 end) as 'aug', " +
                "sum(case when month(`create_time`)=9 then (select sum(invest) from purchases where id = p1.id and state=804 and month(`create_time`)=9) else 0 end) as 'sep', " +
                "sum(case when month(`create_time`)=10 then (select sum(invest) from purchases where id = p1.id and state=804 and month(`create_time`)=10) else 0 end) as 'oct', " +
                "sum(case when month(`create_time`)=11 then (select sum(invest) from purchases where id = p1.id and state=804 and month(`create_time`)=11) else 0 end) as 'nov', " +
                "sum(case when month(`create_time`)=12 then (select sum(invest) from purchases where id = p1.id and state=804 and month(`create_time`)=12) else 0 end) as 'dec' " +
                "from purchases p1 where p1.user_id = ? group by p1.user_id";
        Record dataRecord = Db.findFirst(sql,userId);
        List<Double> datas = monthCal(dataRecord);
        System.out.println(datas.toString());
        return datas;
    }

    private List<Double> monthCal(Record dataRecord){
        List<Double> datas = new ArrayList<Double>();
        if(dataRecord==null){
            for(int i = 0;i<12;i++){
                datas.add(0d);
            }
        }else{
            for(String cName : month){
                double val = dataRecord.getDouble(cName);
                datas.add(val);
            }
        }
        return datas;
    }
}
